﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Data.Schema.UnitTesting;
using QueueUnlimited.ScenarioTests.Helper;
using System.Diagnostics;
using System.Threading;

namespace QueueUnlimited.ScenarioTests
{
    [TestClass]
    public class GarbageCollection_Scenarios : BaseScenarioTestFixture
    {
        [TestMethod]
        public void Test_GC_removes_overflow_queues()
        {
            using (var dataStore = new API.DataStore(ConnectionStringForTests))
            {
                dataStore.Enqueue("SomeEvent", "Ola Pola");
                dataStore.Configuration.Apply(new API.Subscriber("MyFirstSubscriber", "SomeEvent")); // add subscriber
                dataStore.Configuration.Apply(new API.Subscriber("MySecondSubscriber", "SomeEvent")); // add subscriber
                dataStore.Configuration.Apply(new API.Subscriber("MyThirdSubscriber", "SomeEvent")); // add subscriber

                PrintServiceTree("Before GC"); // Tracing for when the test fails

                var rootService = MetaData.GetServiceTree();
                // Before GC:
                {
                    Assert.AreEqual(1, rootService.Children().Count()); // MyFirstSubscriber
                    Assert.IsNotNull(rootService.OverflowService);
                    Assert.AreEqual(1, rootService.OverflowService.Children().Count()); // MySecondSubscriber
                    Assert.IsNotNull(rootService.OverflowService.OverflowService);
                    Assert.AreEqual(1, rootService.OverflowService.OverflowService.Children().Count()); // MyThirdSubscriber
                    Assert.IsNotNull(rootService.OverflowService.OverflowService.OverflowService);

                    // Last overflow service, so no next services!:
                    Assert.IsNull(rootService.OverflowService.OverflowService.OverflowService.OverflowService);
                    Assert.AreEqual(0, rootService.OverflowService.OverflowService.OverflowService.Children().Count());
                }
                dataStore.CollectGarbage(5);
                PrintServiceTree("After first GC"); // Tracing for when the test fails
                dataStore.CollectGarbage(5);
                PrintServiceTree("After second GC"); // Tracing for when the test fails
                dataStore.CollectGarbage(5);
                PrintServiceTree("After third GC"); // Tracing for when the test fails

                rootService = MetaData.GetServiceTree();

                // After GC:
                {
                    Assert.AreEqual(3, rootService.Children().Count());
                    Assert.IsNotNull(rootService.OverflowService);
                    Assert.IsNull(rootService.OverflowService.OverflowService);
                    Assert.AreEqual(0, rootService.OverflowService.Children().Count());
                }
            }
        }

        [TestMethod]
        public void Test_GC_keeps_the_latest_overflow_service()
        {
            using (var dataStore = new API.DataStore(ConnectionStringForTests))
            {
                dataStore.Enqueue("SomeEvent", "Message 1");
                dataStore.Configuration.Apply(new API.Subscriber("MyFirstSubscriber", "SomeEvent")); // add subscriber
                dataStore.Configuration.Apply(new API.Subscriber("MySecondSubscriber", "SomeEvent")); // add subscriber

                PrintServiceTree("Before GC"); // Tracing for when the test fails

                var rootService = MetaData.GetServiceTree();
                var nameOfLatestOverflowService = rootService.OverflowService.OverflowService.Name;

                dataStore.CollectGarbage(5);
                PrintServiceTree("After first GC"); // Tracing for when the test fails
                dataStore.CollectGarbage(5);
                PrintServiceTree("After second GC"); // Tracing for when the test fails
                dataStore.CollectGarbage(5);
                PrintServiceTree("After third GC"); // Tracing for when the test fails

                rootService = MetaData.GetServiceTree();

                // After GC:
                {
                    // Let's test if the overflow service after GC still contained
                    // the first message and that we can add a new subscriber
                    Assert.AreEqual(nameOfLatestOverflowService, rootService.OverflowService.Name);
                    var thirdSubscriber = new API.Subscriber("MyThirdSubscriber", "SomeEvent");
                    dataStore.Configuration.Apply(thirdSubscriber); // add subscriber
                    Thread.Sleep(5 * 1000);

                    Assert.AreEqual(1, dataStore.Count(thirdSubscriber));
                }
            }
        }
    }
}

